using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Web;
using PickGold.Charting.Formulas;

namespace PickGold.Charting
{
	[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
	[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
	public class DataFormula
	{
		private string[] _extraParameters;
		private bool _isEmptyPointIgnored = true;
		private StatisticFormula _statistics;
		private bool _zeroXValues;
		internal CommonElements Common;
		internal const string IndexedSeriesLabelsSourceAttr = "__IndexedSeriesLabelsSource__";

		public DataFormula()
		{
			this._statistics = new StatisticFormula(this);
			this._extraParameters = new string[] { false.ToString(CultureInfo.InvariantCulture) };
		}

		internal void CheckXValuesAlignment(Series[] series)
		{
			if (series.Length > 1)
			{
				for (int i = 0; i < (series.Length - 1); i++)
				{
					if (series[i].Points.Count != series[i + 1].Points.Count)
					{
						throw new ArgumentException(SR.ExceptionFormulaDataSeriesAreNotAlignedDifferentDataPoints(series[i].Name, series[i + 1].Name));
					}
					for (int j = 0; j < series[i].Points.Count; j++)
					{
						if (series[i].Points[j].XValue != series[i + 1].Points[j].XValue)
						{
							throw new ArgumentException(SR.ExceptionFormulaDataSeriesAreNotAlignedDifferentXValues(series[i].Name, series[i + 1].Name));
						}
					}
				}
			}
		}

		private void ConvertToArrays(string inputString, out Series[] seiesArray, out int[] valueArray, bool inputSeries)
		{
			string[] strArray = inputString.Split(new char[] { ',' });
			seiesArray = new Series[strArray.Length];
			valueArray = new int[strArray.Length];
			int index = 0;
			foreach (string str in strArray)
			{
				string[] strArray2 = str.Split(new char[] { ':' });
				if ((strArray2.Length < 1) && (strArray2.Length > 2))
				{
					throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(str));
				}
				int num2 = 1;
				if (strArray2.Length == 2)
				{
					if (strArray2[1].StartsWith("Y", StringComparison.Ordinal))
					{
						strArray2[1] = strArray2[1].TrimStart(new char[] { 'Y' });
						if (strArray2[1].Length == 0)
						{
							num2 = 1;
							goto Label_00DA;
						}
						try
						{
							num2 = int.Parse(strArray2[1], CultureInfo.InvariantCulture);
							goto Label_00DA;
						}
						catch (Exception)
						{
							throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(str));
						}
					}
					throw new ArgumentException(SR.ExceptionFormulaDataSeriesNameNotFound(str));
				}
			Label_00DA:
				valueArray[index] = num2;
				try
				{
					seiesArray[index] = this.Common.DataManager.Series[strArray2[0].Trim()];
				}
				catch (Exception)
				{
					if (inputSeries)
					{
						throw new ArgumentException(SR.ExceptionFormulaDataSeriesNameNotFoundInCollection(str));
					}
					this.Common.DataManager.Series.Add(new Series(strArray2[0]));
					seiesArray[index] = this.Common.DataManager.Series[strArray2[0]];
				}
				index++;
			}
		}

		private void CopyAxisLabels(Series[] inSeries, Series[] outSeries)
		{
			for (int i = 0; (i < inSeries.Length) && (i < outSeries.Length); i++)
			{
				Series series = inSeries[i];
				Series series2 = outSeries[i];
				if (this._zeroXValues)
				{
					series2["__IndexedSeriesLabelsSource__"] = series.Name;
				}
				else
				{
					int num2 = 0;
					foreach (DataPoint point in series.Points)
					{
						if (!string.IsNullOrEmpty(point.AxisLabel))
						{
							if ((num2 < series2.Points.Count) && (point.XValue == series2.Points[num2].XValue))
							{
								series2.Points[num2].AxisLabel = point.AxisLabel;
							}
							else
							{
								num2 = 0;
								foreach (DataPoint point2 in series2.Points)
								{
									if (point.XValue == point2.XValue)
									{
										point2.AxisLabel = point.AxisLabel;
										break;
									}
									num2++;
								}
							}
						}
						num2++;
					}
				}
			}
		}

		public void CopySeriesValues(string inputSeries, string outputSeries)
		{
			Series[] seriesArray;
			Series[] seriesArray2;
			int[] numArray;
			int[] numArray2;
			double[][] numArray3;
			if (inputSeries == null)
			{
				throw new ArgumentNullException("inputSeries");
			}
			if (outputSeries == null)
			{
				throw new ArgumentNullException("outputSeries");
			}
			this.ConvertToArrays(inputSeries, out seriesArray, out numArray, true);
			this.ConvertToArrays(outputSeries, out seriesArray2, out numArray2, false);
			if (seriesArray.Length != seriesArray2.Length)
			{
				throw new ArgumentException(SR.ExceptionFormulaInputOutputSeriesMismatch);
			}
			for (int i = 0; i < seriesArray.Length; i++)
			{
				Series[] seriesArray3 = new Series[] { seriesArray[i], seriesArray2[i] };
				if (seriesArray3[1].Points.Count == 0)
				{
					foreach (DataPoint point in seriesArray3[0].Points)
					{
						DataPoint item = point.Clone();
						item.series = seriesArray3[1];
						seriesArray3[1].Points.Add(item);
					}
				}
			}
			for (int j = 0; j < seriesArray.Length; j++)
			{
				Series[] series = new Series[] { seriesArray[j], seriesArray2[j] };
				this.CheckXValuesAlignment(series);
			}
			this.GetDoubleArray(seriesArray, numArray, out numArray3, true);
			double[][] outputValues = new double[numArray3.Length][];
			for (int k = 0; k < numArray3.Length; k++)
			{
				outputValues[k] = new double[numArray3[k].Length];
				for (int n = 0; n < numArray3[k].Length; n++)
				{
					outputValues[k][n] = numArray3[k][n];
				}
			}
			for (int m = 0; m < seriesArray.Length; m++)
			{
				if (seriesArray2[m].XValueType == ChartValueType.Auto)
				{
					seriesArray2[m].XValueType = seriesArray[m].XValueType;
					seriesArray2[m].autoXValueType = seriesArray[m].autoXValueType;
				}
				if (seriesArray2[m].YValueType == ChartValueType.Auto)
				{
					seriesArray2[m].YValueType = seriesArray[m].YValueType;
					seriesArray2[m].autoYValueType = seriesArray[m].autoYValueType;
				}
				m++;
			}
			this.SetDoubleArray(seriesArray2, numArray2, outputValues, null);
		}

		private static bool DifferentNumberOfSeries(double[][] input)
		{
			for (int i = 0; i < (input.Length - 1); i++)
			{
				if (input[i].Length != input[i + 1].Length)
				{
					return true;
				}
			}
			return false;
		}

		public void FinancialFormula(FinancialFormula formulaName, string inputSeries)
		{
			this.FinancialFormula(formulaName, inputSeries, inputSeries);
		}

		public void FinancialFormula(FinancialFormula formulaName, Series inputSeries)
		{
			this.FinancialFormula(formulaName, inputSeries, inputSeries);
		}

		public void FinancialFormula(FinancialFormula formulaName, string inputSeries, string outputSeries)
		{
			this.FinancialFormula(formulaName, "", inputSeries, outputSeries);
		}

		public void FinancialFormula(FinancialFormula formulaName, Series inputSeries, Series outputSeries)
		{
			this.FinancialFormula(formulaName, "", inputSeries, outputSeries);
		}

		public void FinancialFormula(FinancialFormula formulaName, string parameters, string inputSeries, string outputSeries)
		{
			if (inputSeries == null)
			{
				throw new ArgumentNullException("inputSeries");
			}
			if (outputSeries == null)
			{
				throw new ArgumentNullException("outputSeries");
			}
			FormulaInfo formulaInfo = FormulaHelper.GetFormulaInfo(formulaName);
			if (string.IsNullOrEmpty(parameters))
			{
				parameters = formulaInfo.SaveParametersToString();
			}
			else
			{
				formulaInfo.CheckParameterString(parameters);
			}
			SeriesFieldList list = SeriesFieldList.FromString(this.Common.Chart, inputSeries, formulaInfo.InputFields);
			SeriesFieldList list2 = SeriesFieldList.FromString(this.Common.Chart, outputSeries, formulaInfo.OutputFields);
			if (list != null)
			{
				inputSeries = list.ToString();
			}
			if (list2 != null)
			{
				outputSeries = list2.ToString();
			}
			this.Formula(formulaName.ToString(), parameters, inputSeries, outputSeries);
		}

		public void FinancialFormula(FinancialFormula formulaName, string parameters, Series inputSeries, Series outputSeries)
		{
			if (inputSeries == null)
			{
				throw new ArgumentNullException("inputSeries");
			}
			if (outputSeries == null)
			{
				throw new ArgumentNullException("outputSeries");
			}
			this.FinancialFormula(formulaName, parameters, inputSeries.Name, outputSeries.Name);
		}

		internal void Formula(string formulaName, string parameters, string inputSeries, string outputSeries)
		{
			Series[] seriesArray;
			Series[] seriesArray2;
			int[] numArray;
			int[] numArray2;
			double[][] numArray3;
			double[][] numArray4;
			double[][] outputValues = null;
			string[][] outLabels = null;
			string[] strArray2;
			this.SplitParameters(parameters, out strArray2);
			this.ConvertToArrays(inputSeries, out seriesArray, out numArray, true);
			this.ConvertToArrays(outputSeries, out seriesArray2, out numArray2, false);
			foreach (Series series in seriesArray2)
			{
				if (seriesArray[0] != null)
				{
					series.XValueType = seriesArray[0].XValueType;
				}
			}
			this.GetDoubleArray(seriesArray, numArray, out numArray3);
			if (!DifferentNumberOfSeries(numArray3))
			{
				this.RemoveEmptyValues(numArray3, out numArray4);
			}
			else
			{
				numArray4 = numArray3;
			}
			string name = null;
			for (int i = 0; i < this.Common.FormulaRegistry.Count; i++)
			{
				name = this.Common.FormulaRegistry.GetModuleName(i);
				this.Common.FormulaRegistry.GetFormulaModule(name).Formula(formulaName, numArray4, out outputValues, strArray2, this._extraParameters, out outLabels);
				if (outputValues != null)
				{
					break;
				}
			}
			if (outputValues == null)
			{
				throw new ArgumentException(SR.ExceptionFormulaNotFound(formulaName));
			}
			this.SetDoubleArray(seriesArray2, numArray2, outputValues, outLabels);
			if (this._zeroXValues)
			{
				foreach (Series series2 in seriesArray2)
				{
					if (series2.Points.Count > 0)
					{
						double xValue = series2.Points[series2.Points.Count - 1].XValue;
						this.Common.Chart.DataManipulator.InsertEmptyPoints(1.0, IntervalType.Number, 0.0, IntervalType.Number, 1.0, xValue, series2);
						foreach (DataPoint point in series2.Points)
						{
							point.XValue = 0.0;
						}
					}
				}
			}
			this.CopyAxisLabels(seriesArray, seriesArray2);
		}

		private void GetDoubleArray(Series[] inputSeries, int[] valueIndex, out double[][] output)
		{
			this.GetDoubleArray(inputSeries, valueIndex, out output, false);
		}

		private void GetDoubleArray(Series[] inputSeries, int[] valueIndex, out double[][] output, bool ignoreZeroX)
		{
			output = new double[inputSeries.Length + 1][];
			if (inputSeries.Length != valueIndex.Length)
			{
				throw new ArgumentException(SR.ExceptionFormulaDataItemsNumberMismatch2);
			}
			int count = -2147483648;
			Series series = null;
			foreach (Series series2 in inputSeries)
			{
				if (count < series2.Points.Count)
				{
					count = series2.Points.Count;
					series = series2;
				}
			}
			foreach (DataPoint point in inputSeries[0].Points)
			{
				this._zeroXValues = true;
				if (point.XValue != 0.0)
				{
					this._zeroXValues = false;
					break;
				}
			}
			if (this._zeroXValues && !ignoreZeroX)
			{
				this.CheckXValuesAlignment(inputSeries);
			}
			int index = 0;
			output[0] = new double[count];
			foreach (DataPoint point2 in series.Points)
			{
				if (this._zeroXValues)
				{
					output[0][index] = index + 1.0;
				}
				else
				{
					output[0][index] = point2.XValue;
				}
				index++;
			}
			int num3 = 1;
			foreach (Series series3 in inputSeries)
			{
				output[num3] = new double[series3.Points.Count];
				index = 0;
				foreach (DataPoint point3 in series3.Points)
				{
					if (point3.IsEmpty)
					{
						output[num3][index] = double.NaN;
					}
					else
					{
						try
						{
							output[num3][index] = point3.YValues[valueIndex[num3 - 1] - 1];
						}
						catch (Exception)
						{
							throw new ArgumentException(SR.ExceptionFormulaYIndexInvalid);
						}
					}
					index++;
				}
				num3++;
			}
		}

		private void RemoveEmptyValues(double[][] input, out double[][] output)
		{
			output = new double[input.Length][];
			int index = 0;
			int num2 = 0;
			for (int i = 0; i < input[0].Length; i++)
			{
				bool flag = false;
				index = 0;
				while (index < input.Length)
				{
					if ((index < input[index].Length) && double.IsNaN(input[index][i]))
					{
						flag = true;
					}
					index++;
				}
				if (!flag)
				{
					num2++;
				}
				if (flag)
				{
					index = 1;
					while (index < input.Length)
					{
						input[index][i] = double.NaN;
						index++;
					}
				}
			}
			for (index = 0; index < input.Length; index++)
			{
				output[index] = new double[num2];
				int num4 = 0;
				for (int j = 0; j < input[0].Length; j++)
				{
					if ((j < input[index].Length) && !double.IsNaN(input[1][j]))
					{
						output[index][num4] = input[index][j];
						num4++;
					}
				}
			}
		}

		internal void SetDoubleArray(Series[] outputSeries, int[] valueIndex, double[][] outputValues, string[][] outputLabels)
		{
			if (outputSeries.Length != valueIndex.Length)
			{
				throw new ArgumentException(SR.ExceptionFormulaDataItemsNumberMismatch);
			}
			if (outputSeries.Length < (outputValues.Length - 1))
			{
				throw new ArgumentException(SR.ExceptionFormulaDataOutputSeriesNumberYValuesIncorrect);
			}
			int index = 0;
			foreach (Series series in outputSeries)
			{
				if ((index + 1) > (outputValues.Length - 1))
				{
					return;
				}
				if (series.Points.Count != outputValues[index].Length)
				{
					series.Points.Clear();
				}
				if (series.YValuesPerPoint < valueIndex[index])
				{
					series.YValuesPerPoint = valueIndex[index];
				}
				for (int i = 0; i < outputValues[0].Length; i++)
				{
					if (series.Points.Count != outputValues[index].Length)
					{
						series.Points.AddXY(outputValues[0][i], 0.0);
						if (outputLabels != null)
						{
							series.Points[i].Label = outputLabels[index][i];
						}
						if (double.IsNaN(outputValues[index + 1][i]))
						{
							series.Points[i].IsEmpty = true;
						}
						else
						{
							series.Points[i].YValues[valueIndex[index] - 1] = outputValues[index + 1][i];
						}
					}
					else
					{
						if ((series.Points[i].XValue != outputValues[0][i]) && !this._zeroXValues)
						{
							throw new InvalidOperationException(SR.ExceptionFormulaXValuesNotAligned);
						}
						if (double.IsNaN(outputValues[index + 1][i]))
						{
							series.Points[i].IsEmpty = true;
						}
						else
						{
							series.Points[i].YValues[valueIndex[index] - 1] = outputValues[index + 1][i];
							if (outputLabels != null)
							{
								series.Points[i].Label = outputLabels[index][i];
							}
						}
					}
				}
				index++;
			}
		}

		private void SplitParameters(string parameters, out string[] parameterList)
		{
			parameterList = parameters.Split(new char[] { ',' });
			for (int i = 0; i < parameterList.Length; i++)
			{
				parameterList[i] = parameterList[i].Trim();
			}
		}

		public bool IsEmptyPointIgnored
		{
			get
			{
				return this._isEmptyPointIgnored;
			}
			set
			{
				this._isEmptyPointIgnored = value;
			}
		}

		public bool IsStartFromFirst
		{
			get
			{
				return bool.Parse(this._extraParameters[0]);
			}
			set
			{
				if (value)
				{
					this._extraParameters[0] = true.ToString(CultureInfo.InvariantCulture);
				}
				else
				{
					this._extraParameters[0] = false.ToString(CultureInfo.InvariantCulture);
				}
			}
		}

		public StatisticFormula Statistics
		{
			get
			{
				return this._statistics;
			}
		}
	}
}

